////
/// @group button
////

@use "sass:list";
@use "sass:map";
@use "../utils";
@use "../border-radius";
@use "../spacing";
@use "../theme/a11y";
@use "../theme/theme";
@use "../icon/icon";
@use "../box-shadows";
@use "../media-queries/media-queries";
@use "../interaction/interaction";
@use "../progress/progress";
@use "../overlay/overlay";
@use "../typography/typography";

/// Set to `true` to disable all the styles
/// @type Boolean
$disable-everything: false !default;

/// Set to `true` to disable the text button styles
/// @type Boolean
$disable-text: false !default;

/// Set to `true` to disable the icon button styles
/// @type Boolean
$disable-icon: false !default;

/// Set to `true` to disable the icon-square button styles
/// @type Boolean
$disable-icon-square: false !default;

/// Set to `true` to disable the contained button styles
/// @type Boolean
$disable-contained: false !default;

/// Set to `true` to disable the contained with pressed elevation button styles
/// @type Boolean
$disable-contained-pressed-elevation: false !default;

/// Contained buttons should _normally_ always force dark background colors for
/// the interaction states This means use the default light theme since it is
/// based off of the root background color.
///
/// @type Boolean
$disable-contained-interaction-colors: interaction.$light-surface-base-background-color
  == interaction.$dark-surface-base-background-color !default;

/// Set to `true` to disable the floating button styles
/// @type Boolean
$disable-floating: false !default;

/// Set to `true` to disable the floating button `position: absolute` styles
/// @type Boolean
$disable-floating-absolute-position: false !default;

/// Set to `true` to disable updating the circular progress size within buttons
/// @type Boolean
$disable-circular-progress: progress.$disable-circular !default;

/// Set to `true` to disable the async button styles
/// @type Boolean
$disable-async: $disable-circular-progress !default;

/// Set to `true` to disable `.rmd-button-unstyled` utility class
/// @type Boolean
$disable-unstyled-utility-class: false !default;

/// The default border radius to apply to text buttons
/// @type Number
$text-border-radius: border-radius.get-var(sm) !default;

/// The default horizontal padding to apply to text buttons
/// @type Number
$text-horizontal-padding: spacing.get-var(md) !default;

/// The default vertical padding to apply to text buttons
/// @type Number
$text-vertical-padding: spacing.get-var(none) !default;

/// The default min-height to apply to text buttons
/// @type Number
$text-min-height: 2.25rem !default;

/// The default min-width to apply to text buttons
/// @type Number
$text-min-width: 4rem !default;

/// The default size to set icons that appear as children of text buttons
/// @type Number
$text-icon-size: 1.125rem !default;

/// The default border radius to apply to icon buttons
/// @type Number
$icon-border-radius: border-radius.get-var(full) !default;

/// The default border radius to apply to square icon buttons
/// @type Number
$icon-square-border-radius: $text-border-radius !default;

/// The default height and width of icon buttons. This default value makes them
/// responsive based on the current font size.
/// @type Number
$icon-size: auto !default;

/// The default icon button small size
/// @type Number
$icon-small-size: icon.$size - 0.25rem !default;

/// The default icon button large size
/// @type Number
$icon-large-size: icon.$size + 0.25rem !default;

/// The default icon button font size which is used to update the total size of
/// the button as well.
/// @type Number
$icon-font-size: icon.$size !default;

/// The default padding for icon buttons. The icon button size is determined by
/// adding the padding to the icon size.
/// @type Number
$icon-padding: 0.5em !default;

/// The default material design elevation for the contained button theme. This
/// should be a number from 0 - 24.
/// @type Number
$contained-elevation: 2 !default;

/// The default material design elevation for the contained button theme while
/// pressed. This should be a number from 0 - 24.
/// @type Number
$contained-pressed-elevation: 4 !default;

/// The default background color to apply to contained buttons while the theme is
/// set to clear
/// @type Color
$clear-contained-background-color: theme.$light-theme-surface-color !default;

/// The default text color to apply to contained buttons while the theme is set
/// to clear
/// @type Color
$clear-contained-color: a11y.contrast-color(
  $clear-contained-background-color
) !default;

/// The default size for circular progress components that appear as a child of
/// a text button
/// @type Number
$circular-progress-size: icon.get-var(size) !default;

/// The default viewport margin for a floating action button
/// @type Number
$floating-margin: spacing.get-var(lg) !default;

/// The default z-index for a floating action button
/// @type Number
$floating-z-index: utils.$temporary-element-z-index !default;

/// The default z-index for an absolute positioned floating action button. This
/// should be a number lower than the `$app-bar-fixed-z-index`.
/// @type Number
$floating-absolute-z-index: 5 !default;

/// The default floating action button positions and their margin styles.
/// @type Number
$floating-positions: (
  tl: (
    left: $floating-margin,
    top: $floating-margin,
  ),
  tr: (
    right: $floating-margin,
    top: $floating-margin,
  ),
  bl: (
    bottom: $floating-margin,
    left: $floating-margin,
  ),
  br: (
    bottom: $floating-margin,
    right: $floating-margin,
  ),
) !default;

/// The available configurable css variables and mostly used internally for the
/// `get-var`, `set-var`, and `use-var` utils.
/// @type List
$variables: (
  background-color,
  color,
  border-radius,
  contained-background-color,
  contained-color,
  text-horizontal-padding,
  text-vertical-padding,
  text-min-height,
  text-min-width,
  text-border-radius,
  icon-size,
  icon-padding,
  icon-font-size,
  icon-border-radius,
  icon-square-border-radius,
  fab-offset
);

/// @param {String} name - The supported variable name
/// @param {any} fallback [null] - An optional fallback value
/// @returns {String} a `var()` statement
@function get-var($name, $fallback: null) {
  $var: utils.get-var-name($variables, $name, "button");
  @if $fallback {
    @return var(#{$var}, #{$fallback});
  }

  @return var(#{$var});
}

/// @param {String} name - The supported variable name
/// @param {any} value - The value to set the variable to. Supports `null` which
/// will just be a no-op.
@mixin set-var($name, $value) {
  @if $value {
    #{utils.get-var-name($variables, $name, "button")}: #{$value};
  }
}

/// @param {String} property - The css property to apply the variable to
/// @param {String} name [$property] - The supported variable name
/// @param {any} fallback [null] - An optional fallback value if the variable
/// has not been set
@mixin use-var($property, $name: $property, $fallback: null) {
  #{$property}: get-var($name, $fallback);
}

/// Used to create button that does not have the default browser button styles
///
/// @example scss - Example SCSS Usage
///   .button {
///     @include unstyled($hoverable: true, $css-modules: false);
///   }
///
/// @param {Boolean} hoverable [false] - Pass-through to
/// `interaction.surface($hoverable)`
/// @param {Boolean} css-modules [false] - Pass-through to
/// `interaction.surface($css-modules)`
/// @param {Boolean} box-shadow [interaction.$focus-box-shadow] - Pass-through
/// to `interaction.surface($box-shadow)`
@mixin unstyled(
  $hoverable: false,
  $css-modules: false,
  $box-shadow: interaction.$focus-box-shadow
) {
  @include interaction.surface(
    $hoverable: $hoverable,
    $css-modules: $css-modules,
    $box-shadow: $box-shadow
  );

  & {
    background-color: transparent;
    border-width: 0;
    display: inline-flex;
  }
}

/// Used to apply the text button styles to an element and most likely an
/// internal only mixin.
///
/// @example scss - Example SCSS Usage
///   .button {
///     @include text-styles;
///
///     align-items: center;
///     border-width: 0;
///     display: inline-flex;
///     flex-shrink: 0;
///     justify-content: center;
///   }
@mixin text-styles {
  @include icon.set-var(size, $text-icon-size);
  @include utils.map-to-styles(typography.$button-styles);
  @include use-var(border-radius, text-border-radius, $text-border-radius);
  @include use-var(min-height, text-min-height);
  @include use-var(min-width, text-min-width);

  border: 0;
  padding: get-var(text-vertical-padding) get-var(text-horizontal-padding);
}

/// Conditionally applies the css variables based on feature flags
@mixin variables {
  @if not $disable-everything {
    @include set-var(background-color, transparent);
    @if not $disable-contained {
      @include set-var(
        contained-background-color,
        $clear-contained-background-color
      );
      @include set-var(contained-color, $clear-contained-color);
    }

    @if not $disable-text {
      @include set-var(text-horizontal-padding, $text-horizontal-padding);
      @include set-var(text-vertical-padding, $text-vertical-padding);
      @include set-var(text-min-height, $text-min-height);
      @include set-var(text-min-width, $text-min-width);
    }

    @if not $disable-icon {
      @include set-var(icon-size, $icon-size);
      @include set-var(icon-font-size, $icon-font-size);
      @include set-var(icon-padding, $icon-padding);

      @if not $disable-icon-square {
        @include set-var(icon-square-border-radius, $icon-square-border-radius);
      }
    }

    @if not $disable-floating {
      @include set-var(fab-offset, utils.scrollbar-size());
    }
  }
}

/// Generates all the styles based on feature flags.
///
/// @param {Boolean} disable-layer [false] - Set this to `true` to disable the
/// layer behavior
@mixin styles($disable-layer: false) {
  @if not $disable-everything {
    @include utils.optional-layer(button, $disable-layer) {
      .rmd-button {
        @if not $disable-circular-progress {
          @include progress.set-var(circular-size, $circular-progress-size);
        }

        @include icon.set-var(color, currentcolor);
        @include icon.use-var(gap, spacing);
        @include use-var(background-color);
        @include use-var(color);
        @include use-var(border-radius);

        align-items: center;
        border-width: 0;
        display: inline-flex;
        flex-shrink: 0;
        justify-content: center;

        @if not $disable-text {
          &--text {
            @include text-styles;
          }
        }

        @if not $disable-icon {
          &--icon {
            @include icon.set-var(size, 1em);
            @include set-var(
              border-radius,
              get-var(icon-border-radius, $icon-border-radius)
            );
            @include use-var(font-size, icon-font-size);
            @include use-var(height, icon-size);
            @include use-var(width, icon-size);
            @include use-var(padding, icon-padding);
          }

          @if not $disable-icon-square {
            &--icon-square {
              @include set-var(
                icon-border-radius,
                get-var(icon-square-border-radius)
              );
            }
          }

          @if $icon-small-size {
            &--small {
              font-size: $icon-small-size;
            }
          }

          @if $icon-large-size {
            &--large {
              font-size: $icon-large-size;
            }
          }
        }

        &--responsive {
          @include media-queries.tablet-media {
            @include text-styles;

            height: auto;
            width: auto;
          }
        }

        &:disabled,
        &--disabled {
          @include theme.theme-set-var(outline-color, currentcolor);
          // this was added for the file input
          @include interaction.surface-disabled($clickable: false);
        }

        @if not $disable-contained {
          &--contained {
            // contained buttons should _normally_ always force dark background
            // colors for the interaction states This means use the default light
            // theme since it is based off of the root background color
            @if not $disable-contained-interaction-colors {
              @include interaction.use-light-surface;
            }

            @include set-var(
              background-color,
              get-var(contained-background-color)
            );
            @include set-var(color, get-var(contained-color));

            @include box-shadows.elevation-transition(
              $contained-elevation,
              if(
                $disable-contained-pressed-elevation,
                null,
                $contained-pressed-elevation
              ),
              "&.rmd-button--pressed",
              $pseudo-before: false,
              $position-relative: false
            );
          }
        }

        @if not $disable-async {
          &--async {
            @include overlay.set-var(background-color, transparent);
            @include progress.set-var(color, currentcolor);
          }

          &--async-overlay {
            > * {
              opacity: 0;
            }
          }
        }
      }

      @if not $disable-unstyled-utility-class {
        .rmd-button-unstyled {
          @include unstyled;
        }
      }

      @if not $disable-floating {
        .rmd-fab {
          position: fixed;
          z-index: $floating-z-index;

          @if not $disable-floating-absolute-position {
            &--absolute {
              @include set-var(fab-offset, 0px);

              position: absolute;
              z-index: $floating-absolute-z-index;
            }
          }

          @each $suffix, $styles in $floating-positions {
            &--#{$suffix} {
              $left: null;
              $right: null;

              @each $property, $value in $styles {
                @if $property == left {
                  $left: auto;
                  $right: calc(#{$value} + #{get-var(fab-offset)});

                  left: $value;
                } @else if $property == right {
                  $left: $value;
                  $right: auto;

                  right: calc(#{$value} + #{get-var(fab-offset)});
                } @else {
                  #{$property}: #{$value};
                }
              }

              @if $left and $right {
                @include utils.rtl {
                  left: $left;
                  right: $right;
                }
              }
            }
          }
        }
      }
    }
  }
}
